﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Web;

namespace Shumisen.Web.Form.Modules
{
	/// <summary>
	/// 
	/// </summary>
	/// <seealso cref="http://support.microsoft.com/?id=911816"/>
	// TODO 全面的な見直し
	public class UnhandledExceptionModule : IHttpModule
	{
		private static readonly object initLock = new object();

		private static int _unhandledExceptionCount;

		private static string _sourceName;

		private static volatile bool _initialized;

		public void Init(HttpApplication app)
		{
			if (!_initialized)
			{
				lock (initLock)
				{
					if (!_initialized)
					{
						var webenginePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "webengine.dll");

						if (!File.Exists(webenginePath))
						{
							throw new Exception(String.Format(CultureInfo.InvariantCulture,
							                                  "Failed to locate webengine.dll at '{0}'.  This module requires .NET Framework 2.0.",
							                                  webenginePath));
						}

						var ver = FileVersionInfo.GetVersionInfo(webenginePath);
						_sourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0",
						                            ver.FileMajorPart, ver.FileMinorPart, ver.FileBuildPart);

						if (!EventLog.SourceExists(_sourceName))
						{
							throw new Exception(String.Format(CultureInfo.InvariantCulture,
							                                  "There is no EventLog source named '{0}'. This module requires .NET Framework 2.0.",
							                                  _sourceName));
						}

						AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

						_initialized = true;
					}
				}
			}
		}

		public void Dispose()
		{
		}

		protected virtual void OnUnhandledException(object o, UnhandledExceptionEventArgs e)
		{
			// Let this occur one time for each AppDomain.
			if (Interlocked.Exchange(ref _unhandledExceptionCount, 1) != 0)
			{
				return;
			}

			var message = new StringBuilder("\r\n\r\nUnhandledException logged by UnhandledExceptionModule.dll:\r\n\r\nappId=");

			var appId = (string) AppDomain.CurrentDomain.GetData(".appId");
			if (appId != null)
			{
				message.Append(appId);
			}

			Exception currentException = null;
			for (currentException = (Exception) e.ExceptionObject; currentException != null; currentException = currentException.InnerException)
			{
				message.AppendFormat("\r\n\r\ntype={0}\r\n\r\nmessage={1}\r\n\r\nstack=\r\n{2}\r\n\r\n",
				                     currentException.GetType().FullName,
				                     currentException.Message,
				                     currentException.StackTrace);
			}

			// log4.netを利用したログ出力
			//var Log = new EventLog();
			//Log.Source = _sourceName;
		}
	}
}